#include <SoftwareSerial.h>
#include <OneWire.h>
#include <stdarg.h>

OneWire ds(10);  // on pin 10

const String SW_REV = "0.109";
const char EOL = '@';
#define ANALOG_SENSOR_COUNT 5
#define DELAY_READ_TEMP 5000
int lastAnalogReads[5] = {-1,-1,-1,-1};
int hue = 0;

boolean bStartEventSent = false;

unsigned long last_ts;

byte ledIds[3] = {3,5,6};
byte ledIdx = 0;
#define LED_COUNT 3

#define TX_PIN 2
#define RX_PIN 8

SoftwareSerial ctlSerial(RX_PIN, TX_PIN);

void setup(void) {
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  //ctlSerial.begin(9600);
  sendNodeStartEvent();
  //writeID("ARD002");
}

void blink(void) {
  digitalWrite(13, HIGH);
  delay(3000);
  digitalWrite(13, LOW);
}

void sendNodeStartEvent() {
  if (!bStartEventSent) {
    unsigned long ts = millis();
    Serial.print(getEEPROMID());
    Serial.print("|CTRL|start|sw.rev=" + SW_REV + "|ms=");
    Serial.print(ts);
    Serial.print(EOL);
    Serial.flush();
    Serial.print(getEEPROMID());
    Serial.print("|CTRL|start|temp.samp.period=");
    Serial.print(DELAY_READ_TEMP);
    Serial.print(EOL);
    Serial.flush();
    bStartEventSent = true;
  }
}

void looptest(void) {
  String id = getEEPROMID();
  Serial.print(id);
  delay(1000);
}

void loopEEPROMdiag(void) {
  getEEPROMID();
  Serial.print("\n");
  delay(500);
}

void loop(void) {
  sendTemps();
  drive();
  //sendAnalogs();
}

void drive() {
  const byte RED_LED=0;
  const byte GREEN_LED=1;
  const byte BLUE_LED=2;
  float gpot = ((float) analogRead(5)) / 1024; // pot
  float gpho = ((float) analogRead(4)) / 1024; // photo
  setLedColorHSV(hue,1,0.1);
  hue = (hue++)%360;
}

void sendAnalogs(void) {
  unsigned long ts = millis();
  if (ts - last_ts > 3000) {
    for (byte sensorId=0; sensorId <= ANALOG_SENSOR_COUNT; sensorId++) {
      int sensorValue = analogRead(sensorId);
      if (sensorValue != lastAnalogReads[sensorId]) {
        Serial.print(getEEPROMID());
        Serial.print("|");
        Serial.print("A");
        Serial.print(sensorId);
        Serial.print("|");
        Serial.print(sensorValue);
        Serial.print(EOL);
        Serial.flush();
        lastAnalogReads[sensorId] = sensorValue;
      }
    }
    last_ts = ts;
  }
}

void sendTemps(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;
  
  unsigned long ts = millis();
  if (ts - last_ts > DELAY_READ_TEMP) {
    last_ts  = ts;
    if ( !ds.search(addr)) {
      ds.reset_search();
      blink();
      delay(250);
      return;
    }
    
    Serial.print(getEEPROMID());
    
    Serial.print("|");
    for( i = 0; i < 8; i++) {
      Serial.print(addr[i], HEX);
    }
    Serial.print("|");
    
    if (OneWire::crc8(addr, 7) != addr[7]) {
        Serial.println("CRC is not valid!");
        return;
    }
   
    // the first ROM byte indicates which chip
    switch (addr[0]) {
      case 0x10:
        Serial.print("DS18S20");  // or old DS1820
        type_s = 1;
        break;
      case 0x28:
        Serial.print("DS18B20");
        type_s = 0;
        break;
      case 0x22:
        Serial.print("DS1822");
        type_s = 0;
        break;
      default:
        Serial.print("Device is not a DS18x20 family device.");
        return;
    } 
  
    ds.reset();
    ds.select(addr);
    ds.write(0x44,1);         // start conversion, with parasite power on at the end
    
    delay(1000);     // maybe 750ms is enough, maybe not
    // we might do a ds.depower() here, but the reset will take care of it.
    
    present = ds.reset();
    ds.select(addr);    
    ds.write(0xBE);         // Read Scratchpad
  
    for ( i = 0; i < 9; i++) {           // we need 9 bytes
      data[i] = ds.read();
    }
    unsigned int raw = (data[1] << 8) | data[0];
    if (type_s) {
      raw = raw << 3; // 9 bit resolution default
      if (data[7] == 0x10) {
        // count remain gives full 12 bit resolution
        raw = (raw & 0xFFF0) + 12 - data[6];
      }
    } else {
      byte cfg = (data[4] & 0x60);
      if (cfg == 0x00) raw = raw << 3;  // 9 bit resolution, 93.75 ms
      else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
      else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
      // default is 12 bit resolution, 750 ms conversion time
    }
    celsius = (float)raw / 16.0;
    fahrenheit = celsius * 1.8 + 32.0;
    Serial.print("|");
    Serial.print(celsius);
    ctlSerial.println(celsius);
    Serial.print(EOL);
    Serial.flush();
    //Serial.print(fahrenheit);
  }
}

